package lacus.wd_cinema.service;

import lacus.wd_cinema.dto.movies.MovieAddRequest;
import lacus.wd_cinema.dto.movies.MovieAddResponse;
import lacus.wd_cinema.dto.movies.MovieUpdateRequest;
import lacus.wd_cinema.dto.movies.MovieUpdateResponse;
import lacus.wd_cinema.entity.Movie;
import lacus.wd_cinema.entity.User;
import lacus.wd_cinema.exception.EntityNotFoundException;
import lacus.wd_cinema.exception.OperationNotAllowedException;
import lacus.wd_cinema.repository.MovieRepository;
import lacus.wd_cinema.repository.ScreeningRepository;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Duration;

/**
 * 与电影相关的业务处理类
 * @author lacus
 * @version 0.5
 * @since 0.2
 */
@Service
@Transactional
public class MovieService {
    private final MovieRepository movieRepository;
    private final ScreeningRepository screeningRepository;
    private final LogService logService;

    public MovieService(
            MovieRepository movieRepository,
            ScreeningRepository screeningRepository, LogService logService) {
        this.movieRepository = movieRepository;
        this.screeningRepository = screeningRepository;
        this.logService = logService;
    }

    /**
     * 根据ID获取电影
     * @param id ID
     * @return 电影
     */
    public Movie getMovieById(long id) {
        return movieRepository.findById(id).orElseThrow(
                () -> new EntityNotFoundException("未找到ID为" + id + "的电影")
        );
    }

    /**
     * 对所有的电影进行搜索
     * @param page 页码
     * @param pageSize 页的大小
     * @param keyword 搜索关键字
     * @param search 要搜索的字段
     *      (id/title/director/starring/description)
     * @return 搜索结果页面
     */
    public Page<Movie> searchMovies(
            int page, int pageSize, String keyword, String search) {
        Pageable pageable = PageRequest.of(page - 1, pageSize);
        if (keyword == null || keyword.isBlank()) {
            return movieRepository.findAll(pageable);
        }
        switch (search) {
            case "id" -> {
                return movieRepository.findByIdContaining(keyword, pageable);
            }
            case "title" -> {
                return movieRepository.findByTitleContaining(keyword, pageable);
            }
            case "director" -> {
                return movieRepository.findByDirectorContaining(keyword, pageable);
            }
            case "starring" -> {
                return movieRepository.findByStarringContaining(keyword, pageable);
            }
            case "description" -> {
                return movieRepository.findByDescriptionContaining(keyword, pageable);
            }
        }
        return movieRepository.findAll(pageable);
    }

    /** 添加新的电影 */
    public MovieAddResponse addMovie(
            MovieAddRequest request, User operator) {
        Movie movie = new Movie();
        BeanUtils.copyProperties(request, movie);
        movie.setRuntime(Duration.ofMinutes(request.getRuntime()));
        Movie savedMovie = movieRepository.save(movie);
        logService.log(operator, "添加电影：" + savedMovie.getTitle()); // 记录业务日志
        return MovieAddResponse.from(savedMovie);
    }

    /** 更新电影的信息 */
    public MovieUpdateResponse updateMovie(
            long id, MovieUpdateRequest request, User operator) {
        Movie movie = getMovieById(id);
        BeanUtils.copyProperties(request, movie);
        movie.setRuntime(Duration.ofMinutes(request.getRuntime()));
        logService.log(operator, "更改电影：" + movie.getTitle()); // 记录业务日志
        return MovieUpdateResponse.from(movieRepository.save(movie));
    }

    /** 删除电影，前提是不存在与之关联的放映 */
    public void deleteMovie(long id, User operator) {
        Movie movie = getMovieById(id);
        if (screeningRepository.existsByMovieId(id))
            throw new OperationNotAllowedException("不允许删除已有放映安排的电影");
        else movieRepository.delete(movie);
        logService.log(operator, "删除电影：" + movie.getTitle());
    }
}
